//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_VARIABLE_ARGUMENTS_H
#define _UXS_VARIABLE_ARGUMENTS_H

#pragma once

#include "../../stl_core/ux_stl_core.h"
#include <stdarg.h>

namespace UX_STL
{
namespace UXTypesExt
{

	
	//
	// Variable Arguments list Helper
	//

	namespace _types_hidden_
	{
		template <typename T>	struct _VarArgType			{};

		template <typename T, typename Inner>	struct _VarArgInnerType {};

		template <typename T>
		struct _VarArgInnerType <T, isize>
		{
			typedef isize	inner_type;
			typedef T		type;

			static type Read (va_list ptr)			{ return (type) *(inner_type const *) ptr; }
			static type IncAndRead (va_list &ptr)	{ return (type) va_arg( ptr, inner_type ); }
		};
		
		template <typename T>
		struct _VarArgInnerType <T, double>
		{
			typedef double	inner_type;
			typedef T		type;

			static type Read (va_list ptr)			{ return (type) *(inner_type const *) ptr; }
			static type IncAndRead (va_list &ptr)	{ return (type) va_arg( ptr, inner_type ); }
		};

		template <>	struct _VarArgType <bool>   : _VarArgInnerType <bool,   isize>	{};
		template <>	struct _VarArgType <char>   : _VarArgInnerType <char,   isize>	{};
		template <>	struct _VarArgType <int8>   : _VarArgInnerType <int8,   isize>	{};
		template <> struct _VarArgType <uint8>  : _VarArgInnerType <uint8,  isize>	{};
		template <>	struct _VarArgType <int16>  : _VarArgInnerType <int16,  isize>	{};
		template <>	struct _VarArgType <uint16> : _VarArgInnerType <uint16, isize>	{};
		template <>	struct _VarArgType <int>    : _VarArgInnerType <int,    isize>	{};
		template <>	struct _VarArgType <uint>   : _VarArgInnerType <uint,   isize>	{};
		template <>	struct _VarArgType <int64>  : _VarArgInnerType <int64,  isize>	{};
		template <>	struct _VarArgType <uint64> : _VarArgInnerType <uint64, isize>	{};
		template <>	struct _VarArgType <float>  : _VarArgInnerType <float,  double>	{};
		template <>	struct _VarArgType <double> : _VarArgInnerType <double, double>	{};

		template <typename T> struct _VarArgType<T *> :			_VarArgInnerType<T *, isize>	{};
		template <typename T> struct _VarArgType<const T *> :	_VarArgInnerType< const T *, isize>	{};


	}	// _types_hidden_

	
	//
	// Var Arg
	//

	template <typename T>
	struct TVarArg
	{
	// types
	public:
		typedef	T				value_t;
		typedef TVarArg< T >	Self;

	private:
		typedef _types_hidden_::_VarArgType<T>	_helper_t;


	// variables
	private:
		va_list		_ptr;


	// methods
	public:
		TVarArg (va_list vaList) : _ptr( vaList )
		{}

		~TVarArg ()						{ va_end( _ptr ); }

		operator value_t () const		{ return Get(); }

		value_t	Get () const			{ return _helper_t::Read( _ptr ); }

		template <typename B>
		B		Get () const			{ return _types_hidden_::_VarArgType<B>::Read( _ptr ); }

		template <typename B>
		B		Inc ()					{ return _types_hidden_::_VarArgType<B>::IncAndRead( _ptr ); }

		value_t	Inc ()					{ return _helper_t::IncAndRead( _ptr ); }

		Self &	operator ++ ()			{ _helper_t::IncAndRead( _ptr );  return *this; }
		Self	operator ++ (int)		{ Self  temp(*this);  _helper_t::IncAndRead( _ptr );  return temp; }
	};


//-------------------------------------------------------------------

}	// UXTypesExt
}	// UX_STL

#endif	// _UXS_VARIABLE_ARGUMENTS_H